package com.chhuang.handle;

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.SaTokenException;
import cn.hutool.core.util.StrUtil;
import com.chhuang.component.I18nMessage;
import com.chhuang.core.enums.SaCode;
import com.chhuang.core.exception.SaException;
import com.chhuang.core.bean.SaResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolationException;

/**
 * @ClassName GlobalExceptionHandler
 * @Description 全局异常处理类，先权限校验，然后参数校验，再业务，最后一个兜底
 * @Author Darren Huang
 * @Date 2022/11/25 22:51
 * @Version 1.0
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 获取国际化资源组件
     */
    @Autowired
    private I18nMessage i18nMessage;

    /**
     * sa权限验证异常
     * @param e
     * @return
     */
    @ExceptionHandler(SaTokenException.class)
    public SaResult<Void> handle(SaTokenException e) {
        log.error("SaTokenException::{}", e.getLocalizedMessage());
        if(e instanceof NotLoginException){
            return SaResult.get(SaCode.NOT_LOGIN.getCode(), i18nMessage.get(SaCode.NOT_LOGIN.getCode()));
        }
        return SaResult.get(SaCode.NOT_AUTH.getCode(), i18nMessage.get(SaCode.NOT_AUTH.getCode()));
    }

    /**
     * get请求中的参数校验
     * @param exception
     * @return
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public SaResult<Void> handle(ConstraintViolationException exception){
        StringBuffer message = new StringBuffer();
        exception.getConstraintViolations().forEach(e->message.append(e.getMessage()).append(","));
        String msg = message.substring(0, message.length()-1);
        log.error("ConstraintViolationException::{}", msg);
        return SaResult.get(SaCode.PARAMS_VALID_FAIL.getCode(), msg, null);
    }
    /**
     * form-data格式的参数校验
     * @param exception
     * @return
     */
    @ExceptionHandler(BindException.class)
    public SaResult<Void> handle(BindException exception){
        StringBuffer message = new StringBuffer();
        exception.getAllErrors().forEach(e->message.append(e.getDefaultMessage()).append(","));
        String msg = message.substring(0, message.length()-1);
        log.error("BindException::{}", msg);
        return SaResult.get(SaCode.PARAMS_VALID_FAIL.getCode(), msg, null);
    }

    /**
     * json格式的参数校验
     * @param exception
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public SaResult<Void> handle(MethodArgumentNotValidException exception) {
        StringBuffer message = new StringBuffer();
        exception.getBindingResult().getAllErrors().forEach(e->{
            String error = e.getDefaultMessage();
            if (error!=null && error.startsWith(StrUtil.DELIM_START) && error.endsWith(StrUtil.DELIM_END)) {
                error = i18nMessage.get(error.trim().substring(1, error.length()-1).trim());
            }
            message.append(error).append(StrUtil.COMMA);
        });
        String msg = message.substring(0, message.length()-1);
        log.error("MethodArgumentNotValidException::{}", msg);
        return SaResult.get(SaCode.PARAMS_VALID_FAIL.getCode(), msg, null);
    }

    /**
     * 请求方式异常
     *
     * @param e e
     * @return {@link SaResult}
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public SaResult<Void> handle(HttpRequestMethodNotSupportedException e) {
        log.error("HttpRequestMethodNotSupportedException::{}", e.getLocalizedMessage());
        return SaResult.get(SaCode.METHOD_NOT_SUPPORTED.getCode(), i18nMessage.get(SaCode.METHOD_NOT_SUPPORTED.getCode()));
    }

    /**
     * 请求参数不能为空的异常
     *
     * @param e e
     * @return {@link SaResult}
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public SaResult<Void> handle(MissingServletRequestParameterException e) {
        log.error("MissingServletRequestParameterException::{}", e.getLocalizedMessage());
        return SaResult.get(SaCode.PARAMS_VALID_FAIL.getCode(), i18nMessage.get(SaCode.PARAMS_VALID_FAIL.getCode()));
    }

    /**
     * 业务异常
     * @param e
     * @return
     */
    @ExceptionHandler(SaException.class)
    public SaResult<Void> handle(SaException e) {
        log.error("SaException::{}", e.getLocalizedMessage());
        if (e.getSaCode() == null) {
            return SaResult.error(e.getMessage());
        } else {
            return SaResult.get(e.getSaCode().getCode(), i18nMessage.get(e.getSaCode().getCode()));
        }
    }

    /**
     * 兜底的一个异常处理
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    public SaResult<Void> handle(Exception e) {
        log.error("Exception::{}", e.getLocalizedMessage());
        return SaResult.error(i18nMessage.get(SaCode.INTERNAL_SERVER_ERROR.getCode()));
    }

}
